#pragma once

#include <iostream>
#include <assert.h>
#include "Vector.hpp"

namespace MathLibrary
{
	/*
	template <typename T, int rows, int cols>
	class Matrix
	{
	public:
		enum MatrixInitializer
		{
			EYE,
			ZERO
		};
		Matrix(MatrixInitializer init = EYE)
		{
			//can't generate matrix size greater then 4
			assert(rows < 5 && cols < 5);
			if(init == EYE)
			{
				setEye();
			}
			else if(init == ZERO)
			{
				memset(data, 0, sizeof(data));
			}
		}
		
		~Matrix(){}
		
		void setZero() {memset(data, 0, sizeof(data));}

		void setEye() 
		{
			setZero(); 
			for(int i = 0; i < rows; ++i)
			{
				data[i * rows + i] = T(1);
			}
		}
		Matrix(const Matrix & other)
		{
			memcpy(data,other.data,sizeof(data));
		}
		Matrix & operator = (const  Matrix & other )
		{
			memcpy(data,other.data,sizeof(data));
		}

		Matrix operator * (const Matrix<T, cols, rows> & other) const
		{
			Matrix ret(ZERO);
			for (int i = 0; i < rows; ++i)
			{
				for(int j = 0; j < cols; ++j)
				{
					int ind = i * rows + j;
					for (int k = 0; k < cols; ++k)
					{
						ret.data[ind] += data[i * rows + k] * other.data[k * rows + j];
					}
				}
			}
			return ret;
		}

		Matrix operator + (const Matrix & other) const 
		{
			Matrix ret;
			for (int i = 0; i < rows * cols; ++i)
			{
				ret.data[i] = data[i] + other.data[i];
			}
			return ret;
		}
		Matrix operator - (const Matrix & other) const 
		{
			Matrix ret;
			for (int i = 0; i < rows * cols; ++i)
			{
				ret.data[i] = data[i] - other.data[i];
			}
			return ret;
		}

		Matrix & operator *= (const Matrix & other)
		{
			Matrix tmp = *this * other;
			*this = tmp;
			return *this;
		}
		Matrix & operator += (const Matrix & other)
		{
			for (int i = 0; i < rows * cols; ++i)
			{
				data[i]+= other.data[i];
			}
			return *this;
		}

		Matrix & operator -= (const Matrix & other)
		{
			for (int i = 0; i < rows * cols; ++i)
			{
				data[i] -= other.data[i];
			}
			return *this;
		}

		Vector4<T> operator * (const Vector4<T> & other) const
		{
			assert(cols == 4);
			Vector4<T> ret;
			T * retData = &ret.x;
			for (int i = 0; i < rows; ++i)
			{
				for(int j = 0; j < cols; ++j)
				{
					int ind = i * rows + j;
					retData[i] += data[i * rows + j] * (&other.x)[j];
				}
			}
			return ret;
		}

		Matrix operator * (const Vector2<T> & other);
		Matrix operator * (const Vector3<T> & other);
		
		Matrix & operator << (const T & vals)
		{
			//assert(sizeof(vals) == sizeof(data));
			memcpy(data,&vals, sizeof(data));
			return *this;
		}

		friend std::ostream & operator<<(std::ostream &os, const Matrix& m)
		{
			
			for(int i = 0; i < rows; ++i)
			{
				os << "[ ";
				for(int j = 0; j < cols ; ++j)
				{
					os << m.data[i * rows + j] << " " ;
				}
				os << "]";
				os << endl;
			}
			return os;
		}
		
	private:
		T data[rows * cols];
	};

	typedef Matrix<float, 2, 2> Matrix2f;
	typedef Matrix<double, 2, 2> Matrix2d;
	typedef Matrix<int, 2, 2> Matrix2i;
	typedef Matrix<float, 3, 3> Matrix3f;
	typedef Matrix<double, 3, 3> Matrix3d;
	typedef Matrix<int, 3, 3> Matrix3i;
	typedef Matrix<float, 4, 4> Matrix4f;
	typedef Matrix<double, 4, 4> Matrix4d;
	typedef Matrix<int, 4, 4> Matrix4i;
	*/
}
